package com.oanda.blackberry.view;

import java.util.Timer;
import java.util.TimerTask;

import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.Menu;
import net.rim.device.api.ui.container.HorizontalFieldManager;
import net.rim.device.api.ui.container.VerticalFieldManager;

import com.oanda.blackberry.OandaBlackBerryApplication;
import com.oanda.blackberry.restapi.PositionsListResponse;
import com.oanda.blackberry.restapi.Quote;
import com.oanda.blackberry.restapi.Rate;
import com.oanda.blackberry.restapi.Trade;
import com.oanda.blackberry.restapi.TradeListResponse;
import com.oanda.blackberry.restapi.TradePollResponse;
import com.oanda.blackberry.ui.OandaMainScreen;
import com.oanda.blackberry.util.AbstractViewPanel;
import com.oanda.blackberry.util.DefaultController;
import com.oanda.blackberry.util.Model;
import com.oanda.blackberry.util.PropertyChangeEvent;
import com.oanda.blackberry.util.log.Logger;

public class TradesView implements AbstractViewPanel {
    DefaultController controller;
    VerticalFieldManager listManager = new VerticalFieldManager();

    HorizontalFieldManager hStatus = new HorizontalFieldManager();
    LabelField statusLabel = new LabelField();
    TradesListField list;
    Timer updateTimer = new Timer();

    TimerTask updateTask = new TimerTask() {
        public synchronized void run() {
            if (OandaBlackBerryApplication.isInForeground) {
                TradesView.this.tradePoll();
            } else {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
    };

    Timer updateTimerPositions = new Timer();

    TimerTask updateTaskPositions = new TimerTask() {
        public void run() {
            TradesView.this.tradePositionsPoll();
        }
    };

    Timer quoteTimer = new Timer();

    TimerTask quoteTask = new TimerTask() {
        public synchronized void run() {
            if (OandaBlackBerryApplication.isInForeground) {
                TradesView.this.quoteUpdates();
            } else {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
    };

    private long UPDATE_TIME = 10000L;
    private long UPDATE_TIME_QUOTE = 2000L;

    boolean isPosition = false;
    TradesViewScreen screen;
    private boolean emptyListMessageDidsplayed = false;

    MenuItem viewDetails = new MenuItem("View Details", 10, 1000) {
        public void run() {
            if (TradesView.this.list == null)
                return;
            TradeListResponse details = (TradeListResponse) TradesView.this.list
                    .getTradeListSelected();
            Quote detailsQuote = TradesView.this.list.getQuote(details.getSymbol());
            if ((details != null) && (detailsQuote != null)) {
                Object[] o = new Object[2];
                o[0] = details;
                o[1] = detailsQuote;
                TradesView.this.controller.viewTradeDetails(o);
            } else {
                DefaultController.inform("Please wait for retrieving details!");
            }
        }
    };

    MenuItem cancelTrade = new MenuItem("Close Trade", 10, 1001) {
        public void run() {
            if (4 == Dialog.ask(3, "Are you sure you want to close this trade?")) {
                if ((!TradesView.this.isPosition) && (TradesView.this.list != null)) {
                    TradeListResponse trade = (TradeListResponse) TradesView.this.list
                            .getTradeListSelected();
                    if (trade != null)
                        TradesView.this.controller.cancelTrade(trade);
                    else
                        DefaultController.inform("Please wait for retrieving details!");
                }
            }
        }
    };

    MenuItem cancelPosition = new MenuItem("Close Position", 10, 1001) {
        public void run() {
            if (4 == Dialog.ask(3, "Are you sure you want to close this position?")) {
                if (TradesView.this.isPosition)
                    TradesView.this.controller
                            .cancelPosition((PositionsListResponse) TradesView.this.list
                                    .getTradeListSelected());
            }
        }
    };

    MenuItem backMenuItem = new MenuItem("Back", 10, 10000) {
        public void run() {
            TradesView.this.popScreen();
        }
    };

    public void notifyTimerTask() {
        if (this.updateTask != null) {
            synchronized (this.updateTask) {
                this.updateTask.notifyAll();
            }
        }
        if (this.quoteTask != null) {
            synchronized (this.quoteTask) {
                this.quoteTask.notifyAll();
            }
        }
    }

    public TradesView(DefaultController controller) {
        this.controller = controller;
    }

    private void initScreen() {
        this.screen = new TradesViewScreen(this);
        this.screen.updateTitle("Trades");

        this.screen.add(this.listManager);
    }

    private void setTrades(TradeListResponse[] trades) {
        if (this.screen != null)
            this.screen.hideThrobber();
        if (trades == null) {
            DefaultController.inform("No trades!");
        }

        TradesView callback = this;
        UiApplication.getUiApplication().invokeLater(new Runnable() {
            private TradeListResponse[] val$trades;
            private TradesView val$callback;

            public void run() {
                if ((TradesView.this.list == null) && (this.val$trades != null)
                        && (this.val$trades.length > 0)) {
                    TradeListResponse.sort(this.val$trades);
                    TradesView.this.list = new TradesListField(this.val$trades);
                    TradesView.this.list.setCallback(this.val$callback);
                    TradesView.this.listManager.add(TradesView.this.list.getList());
                } else {
                    TradesView.this.list.update(this.val$trades);
                }
            }
        });
    }

    private void setPositions(final PositionsListResponse[] positions) {
        if (this.screen != null)
            this.screen.hideThrobber();
        if (positions == null) {
            DefaultController.inform("no position entries");
        }

        final TradesView callback = this;
        UiApplication.getUiApplication().invokeLater(new Runnable() {

            public void run() {
                if ((positions != null) && (positions.length > 0)) {
                    int selectedIndex = 0;

                    if ((TradesView.this.list != null)
                            && (TradesView.this.list.getList() != null)
                            && (TradesView.this.list.getList().getSize() > 0)
                            && (!TradesView.this
                                    .isSamePositions(
                                            (PositionsListResponse[]) (PositionsListResponse[]) TradesView.this.list
                                                    .getTradeListResponses(), positions))) {
                        selectedIndex = TradesView.this.list.getList().getSelectedIndex();
                        TradesView.this.listManager.deleteAll();
                        TradesView.this.list = null;
                    }

                    if ((TradesView.this.list == null) && (positions != null)
                            && (positions.length > 0)) {
                        TradesView.this.list = new TradesListField(positions);
                        TradesView.this.list.setCallback(callback);
                        TradesView.this.listManager.add(TradesView.this.list.getList());
                        if ((selectedIndex > -1)
                                && (selectedIndex < TradesView.this.list.getList().getSize()))
                            TradesView.this.list.getList().setSelectedIndex(selectedIndex);
                    }
                }
            }
        });
    }

    private boolean isSamePositions(PositionsListResponse[] p1, PositionsListResponse[] p2) {
        if ((p1 == null) && (p2 == null)) {
            return true;
        }
        if ((p1 != null) && (p2 != null) && (p1.length == p2.length)) {
            for (int i = 0; i < p2.length; i++) {
                if ((p2[i].getSymbol().equals(p1[i].getSymbol()))
                        && (p2[i].getUnits() == p1[i].getUnits())) {
                    if (i == p2.length - 1)
                        return true;
                } else
                    return false;

            }

        }

        return false;
    }

    private void startQuoteUpdateThread() {
        if (this.quoteTimer == null) {
            this.quoteTimer = new Timer();
        }

        if (this.quoteTask == null)
            this.quoteTask = new TimerTask() {
                public void run() {
                    TradesView.this.quoteUpdates();
                }
            };
        try {
            this.quoteTimer.schedule(this.quoteTask, 1000L, this.UPDATE_TIME_QUOTE);
        } catch (IllegalStateException e) {
        }
    }

    private void stopTradePollThread() {
        Logger.log("trades view stopTradePoll on UI EngineAttached cancelling");
        if (this.updateTask != null) {
            this.updateTask.cancel();
            this.updateTask = null;
        }

        if (this.updateTimer != null) {
            Logger.log("cancelling");
            this.updateTimer.cancel();
            this.updateTimer = null;
            Logger.log("Canceled");
        }
    }

    private void startTradePollThread() {
        Logger.log("strart trade poll thread");

        if (this.updateTimer == null) {
            this.updateTimer = new Timer();
        }
        if (this.updateTask == null)
            this.updateTask = new TimerTask() {
                public void run() {
                    TradesView.this.tradePoll();
                }
            };
        try {
            this.updateTimer.schedule(this.updateTask, 1000L, this.UPDATE_TIME);
        } catch (IllegalStateException e) {
        }
    }

    private void stopQuoteUpdateThread() {
        Logger.log("trades view quoteUpdateThread on UI EngineAttached cancelling");
        if (this.quoteTimer != null) {
            Logger.log("cancelling");
            if (this.quoteTask != null) {
                this.quoteTask.cancel();
            }
            this.quoteTimer.cancel();
            this.quoteTimer = null;
            this.quoteTask = null;
            Logger.log("Canceled");
        }
    }

    private void tradePoll() {
        if (UiApplication.getUiApplication().getActiveScreen().equals(this.screen)) {
            this.controller.tradePoll();
            this.controller.turnOnBacklight();
        }
    }

    private void tradePositionsPoll() {
        if (UiApplication.getUiApplication().getActiveScreen().equals(this.screen)) {
            this.controller.positionsList();
            this.controller.turnOnBacklight();
        }
    }

    private void quoteUpdates() {
        if (UiApplication.getUiApplication().getActiveScreen().equals(this.screen)) {
            String s = getListSymbols();
            if ((s != null) && (s.length() > 0)) {
                this.controller.quote(Model.getModel().getSessionToken(), s, null);
                this.controller.turnOnBacklight();
            }
        }
    }

    public void modelPropertyChange(PropertyChangeEvent evt) {
        if (evt.getPropertyName().equals("TradeListException")) {
            if (this.list == null) {
                String message = "error occured";
                if ((evt.getNewValue() != null) && ((evt.getNewValue() instanceof String))) {
                    message = (String) evt.getNewValue();
                }

                if (this.screen != null) {
                    this.screen.diplayError(message, 3000);
                }
                final String fMessage = message;
                Runnable r = new Runnable() {

                    public void run() {
                        String askText = "Retry?";
                        if ((fMessage != null) && (fMessage.length() > 0)) {
                            askText = askText + "(" + fMessage + ")";
                        }
                        int i = Dialog.ask(3, askText, 4);
                        if (i == 4) {
                            if (TradesView.this.isPosition)
                                TradesView.this.controller.positionsList();
                            else
                                TradesView.this.controller.tradeList(null, null, null, null);
                        } else if (i == -1) {
                            TradesView.this.popScreen();
                        }
                    }
                };
                this.controller.invokeLater(r);
            }

        } else if (evt.getPropertyName().equals("setTradeListError")) {
            if (this.screen != null)
                this.screen.diplayError((String) evt.getNewValue(), 2500);
        } else if (evt.getPropertyName().equals("setRateQuote")) {
            if ((evt.getNewValue() != null) && ((evt.getNewValue() instanceof Rate))) {
                Rate rate = (Rate) evt.getNewValue();
                if ((this.list != null) && (rate != null))
                    this.list.setQuotes(rate.getQuotes());
            }
        } else if (evt.getPropertyName().equals("setTradePollResponse")) {
            if ((evt.getNewValue() != null) && ((evt.getNewValue() instanceof TradePollResponse))) {
                TradePollResponse response = (TradePollResponse) evt.getNewValue();
                updateList(response);
            }
        } else if (evt.getPropertyName().equals("removeTradeListStatus")) {
            if (this.screen != null)
                this.screen.removeStatusField();
        } else if (evt.getPropertyName().equals("setTradeListStatus")) {
            if ((evt.getNewValue() != null) && ((evt.getNewValue() instanceof String))) {
                if (this.screen == null)
                    return;

                String s = (String) evt.getNewValue();
                if ((s != null) && (s.length() > 0) && (this.list == null))
                    this.screen.setStatusField((String) evt.getNewValue());
                else {
                    this.screen.removeStatusField();
                }
            }
        } else if ((!this.isPosition) && (evt.getPropertyName().equals("setTradeList"))) {
            if ((evt.getNewValue() != null) && ((evt.getNewValue() instanceof TradeListResponse[]))) {
                setTrades((TradeListResponse[]) (TradeListResponse[]) evt.getNewValue());
            } else if (UiApplication.getUiApplication().getActiveScreen().equals(this.screen)) {
                this.controller.invokeLater(new Runnable() {
                    public void run() {
                        TradesView.this.list = null;
                        if (TradesView.this.listManager != null)
                            TradesView.this.listManager.deleteAll();
                    }
                });

                StatusView2.showInfoDialog("You can create a new trade from quotes screen.",
                        new OKDialogListener() {
                            public void performAction(Object o) {
                                TradesView.this.popScreen();
                            }
                        }, false);
            }

            startTradePollThread();
            startQuoteUpdateThread();
        } else if (evt.getPropertyName().equals("showTradesView")) {
            initScreen();
            this.controller.pushScreen(this.screen);
            this.screen.updateTitle("Trades");
        } else if (evt.getPropertyName().equals("showPositionsView")) {
            this.isPosition = true;
            initScreen();
            this.controller.pushScreen(this.screen);
            this.screen.updateTitle("Positions");
        } else if (evt.getPropertyName().equals("removePositionsListStatus")) {
            if (this.screen != null)
                this.screen.removeStatusField();
        } else if (evt.getPropertyName().equals("setPositionsListStatus")) {
            if (this.screen != null)
                this.screen.setStatusField((String) evt.getNewValue());
        } else if ((this.isPosition) && (evt.getPropertyName().equals("setPositionsList"))) {
            if ((evt.getNewValue() != null)
                    && ((evt.getNewValue() instanceof PositionsListResponse[]))) {
                setPositions((PositionsListResponse[]) (PositionsListResponse[]) evt.getNewValue());
                startQuoteUpdateThread();

                new Thread(new Runnable() {
                    public void run() {
                        try {
                            Thread.sleep(TradesView.this.UPDATE_TIME);
                        } catch (InterruptedException e) {
                        }
                        TradesView.this.tradePositionsPoll();
                    }
                }).start();
            } else if (UiApplication.getUiApplication().getActiveScreen().equals(this.screen)) {
                Runnable r = new Runnable() {
                    public void run() {
                        TradesView.this.list = null;
                        if (TradesView.this.listManager != null)
                            TradesView.this.listManager.deleteAll();
                    }
                };
                this.controller.invokeLater(r);

                StatusView2.showInfoDialog("No Open Positions.", new OKDialogListener() {
                    public void performAction(Object o) {
                        TradesView.this.popScreen();
                    }
                }, false);
            }

        } else if (evt.getPropertyName().equals("positionsClosed")) {
            if ((evt.getNewValue() != null) && ((evt.getNewValue() instanceof String))) {
                if (this.list != null)
                    this.list.removeClosedPositions((String) evt.getNewValue());
            }
        } else if (evt.getPropertyName().equals("tradeClosed")) {
            if ((evt.getNewValue() != null) && ((evt.getNewValue() instanceof String))) {
                if (this.list != null) {
                    this.list.removeClosedTrade((String) evt.getNewValue());
                }
            }

        } else if ((evt != null) && (evt.getPropertyName().equals("showThrobber"))) {
            if (this.screen != null)
                this.screen.showThrobber();
        } else if ((evt != null) && (evt.getPropertyName().equals("hideThrobber"))
                && (this.screen != null)) {
            this.screen.hideThrobber();
        }
    }

    public void popScreen() {
        onClose();
    }

    public void onClose() {
        this.isPosition = false;
        if (this.screen != null) {
            this.controller.popScreen(this.screen);
            this.screen.onClose();
        }
        this.screen = null;
    }

    private void updateList(TradePollResponse response) {
        if (response != null) {
            if ((response.getClosed() != null) && (response.getClosed().length > 0)) {
                if (this.list != null) {
                    this.list.remove(response.getClosed());
                }
            }

            if ((response.getOpened() != null) && (response.getOpened().length > 0)) {
                String maxOpenedId = null;
                String maxCount = null;
                if (response.getMaxOpenedId() == 0L) {
                    maxOpenedId = null;
                } else {
                    maxOpenedId = Long.toString(response.getMaxOpenedId());
                    long l = response.getMaxTradeId() - Trade.getMaxTradeId();
                    maxCount = Long.toString(l);
                }

                this.controller.tradeList(maxOpenedId, maxCount, null, null);
            }

            if ((response.getUpdated() != null) && (response.getUpdated().length > 0)) {
                String maxCount = String.valueOf(response.getUpdated().length);
                this.controller.tradeList(null, maxCount, null, response.getAllUpdatedIds());
            }

            if (response.getMaxTradeId() > Trade.getMaxTradeId()) {
                String maxOpenedId = null;
                String maxCount = null;
                if (response.getMaxOpenedId() == 0L) {
                    maxOpenedId = null;
                } else {
                    maxOpenedId = Long.toString(response.getMaxOpenedId());
                    long l = response.getMaxTradeId() - Trade.getMaxTradeId();
                    maxCount = Long.toString(l);
                }
                this.controller.tradeList(maxOpenedId, maxCount, null, null);
            }
        }
    }

    private String getListSymbols() {
        StringBuffer buffer = new StringBuffer();

        if (this.list == null)
            return null;

        Object[] temp = this.list.getTradeListResponses();
        if ((temp != null) && ((temp instanceof TradeListResponse[]))) {
            TradeListResponse[] data = (TradeListResponse[]) (TradeListResponse[]) this.list
                    .getTradeListResponses();
            for (int i = 0; (data != null) && (i < data.length); i++) {
                String object = data[i].getSymbol();
                buffer.append(object);
                buffer.append(',');
            }
        } else if ((temp != null) && ((temp instanceof PositionsListResponse[]))) {
            PositionsListResponse[] data = (PositionsListResponse[]) (PositionsListResponse[]) this.list
                    .getTradeListResponses();
            for (int i = 0; (data != null) && (i < data.length); i++) {
                String object = data[i].getSymbol();
                buffer.append(object);
                buffer.append(',');
            }

        }

        if (buffer.length() > 1) {
            buffer = buffer.deleteCharAt(buffer.length() - 1);
        }
        return buffer.toString();
    }

    private class TradesViewScreen extends OandaMainScreen {
        private final TradesView tradesView;

        private TradesViewScreen(TradesView tradesView) {
            this.tradesView = tradesView;
        }

        protected void onUiEngineAttached(boolean attached) {
            if (attached) {
                showThrobberPlain();
                if (tradesView.isPosition)
                    tradesView.controller.positionsList();
                else
                    tradesView.controller.tradeList(null, null, null, null);
            } else {
                Logger.log("Trades View onUiEngineAttached false");
                tradesView.stopTradePollThread();

                tradesView.stopQuoteUpdateThread();
                tradesView.list = null;
                tradesView.listManager.deleteAll();

                tradesView.isPosition = false;
            }
        }

        protected void makeMenu(Menu menu, int instance) {
            if (!tradesView.isPosition) {
                if ((tradesView.list != null) && (tradesView.list.getList() != null)
                        && (tradesView.list.getList().getSize() > 0)) {
                    menu.add(tradesView.viewDetails);
                    menu.add(tradesView.cancelTrade);
                }
            } else if ((tradesView.list != null) && (tradesView.list.getList() != null)
                    && (tradesView.list.getList().getSize() > 0)) {
                menu.add(tradesView.cancelPosition);
            }

            menu.add(tradesView.backMenuItem);
        }
    }
}
